﻿using System.Linq;
using System.Windows.Documents;

using agsXMPP.protocol.extensions.chatstates;

using VSTalk.Engine.Core.Context;
using VSTalk.Engine.Core.Feed;
using VSTalk.Engine.ViewModel.Messenger.ThreadRenderer.BlockBuilder;
using VSTalk.Engine.ViewModel.Messenger.ThreadRenderer.Model;

namespace VSTalk.Engine.ViewModel.Messenger.ThreadRenderer.Command
{
    public class RenderXmppMessage : BaseRenderingCommand
    {
        private IMessage _message;

        private ContentBlockBuilder _contentBlockBuilder;
        private StatusBlockBuilder _statusBlockBuilder;
        private SubjectBlockBuilder _subjectBlockBuilder;

        public IModelContext ModelContext
        {
            get { return AppServices.Get<IModelContext>(); }
        }

        public RenderXmppMessage(ConversationModel conversationModel, IMessage message)
                : base(conversationModel)
        {
            _message = message;

            var client = ModelContext.GetClientById(message.ClientId);
            
            _contentBlockBuilder = new ContentBlockBuilder(client);
            _statusBlockBuilder = new StatusBlockBuilder(client);
            _subjectBlockBuilder = new SubjectBlockBuilder(client);
        }

        public override void Execute()
        {
            if (!string.IsNullOrEmpty(_message.XmppMessage.Subject))
            {
                RenderSubject();
            }
            if (!string.IsNullOrEmpty(_message.XmppMessage.Body))
            {
                RenderContent();
            }
            if (_message.XmppMessage.Chatstate != Chatstate.None)
            {
                RemovePresentStatus();
                if (_message.XmppMessage.Chatstate == Chatstate.composing)
                {
                    RenderStatus();
                }
            }
        }

        private void RenderStatus()
        {
            var messageSection = GetOrAddStatusSection();
            var block = _statusBlockBuilder.CreateBlock(_message);
            messageSection.Blocks.Add(block);
        }
        
        private void RemovePresentStatus()
        {
            var status = GetStatusSection();
            if (status == null)
            {
                return;
            }
            status.Blocks.Clear();
        }

        private void RenderSubject()
        {
            var messageSection = GetOrAddMessageSection();
            var block = _subjectBlockBuilder.CreateBlock(_message);
            messageSection.Blocks.Add(block);
        }

        private void RenderContent()
        {
            var messageSection = GetOrAddMessageSection();
            var block = _contentBlockBuilder.CreateBlock(_message);
            messageSection.Blocks.Add(block);
        }

        private Section GetStatusSection()
        {
            var section = ConversationModel.Sections
                .FirstOrDefault(conversationSection => conversationSection.Type == SectionType.Status);
            if (section == null)
            {
                return null;
            }
            return section.Content;
        }

        private Section GetOrAddMessageSection()
        {
            var target = ConversationModel.Sections
                    .LastOrDefault(conversationSection => conversationSection.Type == SectionType.Message);
            if (target != null)
            {
                return target.Content;
            }

            var newSection = new ConversationSection
            {
                Content = new Section(),
                Type = SectionType.Message
            };
            var status = ConversationModel.Sections
                .LastOrDefault(section => section.Type == SectionType.Status);
            if (status == null)
            {
                ConversationModel.AddLast(newSection);
            }
            else
            {
                ConversationModel.AddBefore(newSection, status);
            }
            return newSection.Content;
        }

        private Section GetOrAddStatusSection()
        {
            var target = ConversationModel.Sections
                    .LastOrDefault(conversationSection => conversationSection.Type == SectionType.Status);
            if (target != null)
            {
                return target.Content;
            }

            var newSection = new ConversationSection
            {
                Content = new Section(),
                Type = SectionType.Status
            };
            ConversationModel.AddLast(newSection);
            return newSection.Content;
        }
    }
}